home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / umich / network / ka9q / nhclb120.zoo / tcpsubr.c < prev    next >
C/C++ Source or Header  |  1992-06-18  |  7KB  |  327 lines

  1. #include "global.h"
  2. #include "timer.h"
  3. #include "mbuf.h"
  4. #include "netuser.h"
  5. #include "internet.h"
  6. #include "tcp.h"
  7.  
  8.  
  9. static int16 hash_tcb();
  10. struct tcb *tcbs[NTCB];
  11. int16 tcp_mss = DEF_MSS;    /* Maximum segment size to be sent with SYN */
  12. int32 tcp_irtt = DEF_RTT;    /* Initial guess at round trip time */
  13.  
  14. /* Lookup connection, return TCB pointer or NULLTCB if nonexistant */
  15. struct tcb *
  16. lookup_tcb(conn)
  17. struct connection *conn;
  18. {
  19.     register struct tcb *tcb;
  20.     int16 hash_tcb();    
  21.  
  22.     tcb = tcbs[hash_tcb(conn)];
  23.     while(tcb != NULLTCB){
  24.         /* Yet another structure compatibility hack */
  25.         if(conn->local.address == tcb->conn.local.address
  26.          && conn->remote.address == tcb->conn.remote.address
  27.          && conn->local.port == tcb->conn.local.port
  28.          && conn->remote.port == tcb->conn.remote.port)
  29.             break;
  30.         tcb = tcb->next;
  31.     }
  32.     return tcb;
  33. }
  34.  
  35. /* Create a TCB, return pointer. Return pointer if TCB already exists. */
  36. struct tcb *
  37. create_tcb(conn)
  38. struct connection *conn;
  39. {
  40.     register struct tcb *tcb;
  41.     void tcp_timeout(),tcp_msl();
  42.     void link_tcb();
  43.  
  44.     if((tcb = lookup_tcb(conn)) != NULLTCB)
  45.         return tcb;
  46.     if((tcb = (struct tcb *)calloc(1,sizeof (struct tcb))) == NULLTCB)
  47.         return NULLTCB;
  48.     ASSIGN(tcb->conn,*conn);
  49.  
  50.     tcb->cwind = tcb->mss = tcp_mss;
  51.     tcb->ssthresh = 65535;
  52.     tcb->srtt = tcp_irtt;
  53.     /* Initialize timer intervals */
  54.     tcb->timer.start = tcb->srtt / MSPTICK;
  55.     tcb->timer.func = tcp_timeout;
  56.     tcb->timer.arg = (char *)tcb;
  57.     tcb->rtt_timer.start = MAX_TIME; /* Largest possible value */
  58.  
  59.     link_tcb(tcb);
  60.     return tcb;
  61. }
  62.  
  63. /* Close our TCB */
  64. void
  65. close_self(tcb,reason)
  66. register struct tcb *tcb;
  67. char reason;
  68. {
  69.     struct reseq *rp,*rp1;
  70.  
  71.     stop_timer(&tcb->timer);
  72.     stop_timer(&tcb->rtt_timer);
  73.     tcb->reason = reason;
  74.  
  75.     /* Flush reassembly queue; nothing more can arrive */
  76.     for(rp = tcb->reseq;rp != NULLRESEQ;rp = rp1){
  77.         rp1 = rp->next;
  78.         free_p(rp->bp);
  79.         free((char *)rp);
  80.     }
  81.     tcb->reseq = NULLRESEQ;
  82.     setstate(tcb,CLOSED);
  83. }
  84.  
  85. /* Determine initial sequence number */
  86. int32
  87. iss()
  88. {
  89.     static int32 seq;
  90.  
  91.     seq += 250000;
  92.     return seq;
  93. }
  94.  
  95. /* Sequence number comparisons
  96.  * Return true if x is between low and high inclusive,
  97.  * false otherwise
  98.  */
  99. int
  100. seq_within(x,low,high)
  101. register int32 x,low,high;
  102. {
  103.     if(low <= high){
  104.         if(low <= x && x <= high)
  105.             return 1;
  106.     } else {
  107.         if(low >= x && x >= high)
  108.             return 1;
  109.     }
  110.     return 0;
  111. }
  112. int
  113. seq_lt(x,y)
  114. register int32 x,y;
  115. {
  116.     return (long)(x-y) < 0;
  117. }
  118. int
  119. seq_le(x,y)
  120. register int32 x,y;
  121. {
  122.     return (long)(x-y) <= 0;
  123. }
  124. int
  125. seq_gt(x,y)
  126. register int32 x,y;
  127. {
  128.     return (long)(x-y) > 0;
  129. }
  130. int
  131. seq_ge(x,y)
  132. register int32 x,y;
  133. {
  134.     return (long)(x-y) >= 0;
  135. }
  136.  
  137. /* Hash a connect structure into the hash chain header array */
  138. static int16
  139. hash_tcb(conn)
  140. struct connection *conn;
  141. {
  142.     register int16 hval;
  143.  
  144.     /* Compute hash function on connection structure */
  145.     hval = hiword(conn->remote.address);
  146.     hval ^= loword(conn->remote.address);
  147.     hval ^= hiword(conn->local.address);
  148.     hval ^= loword(conn->local.address);
  149.     hval ^= conn->remote.port;
  150.     hval ^= conn->local.port;
  151.     hval %= NTCB;
  152.     return hval;
  153. }
  154. /* Insert TCB at head of proper hash chain */
  155. void
  156. link_tcb(tcb)
  157. register struct tcb *tcb;
  158. {
  159.     register struct tcb **tcbhead;
  160.     int16 hash_tcb();
  161.     char i_state;
  162.  
  163.     tcb->prev = NULLTCB;
  164.     i_state = disable();
  165.     tcbhead = &tcbs[hash_tcb(&tcb->conn)];
  166.     tcb->next = *tcbhead;
  167.     if(tcb->next != NULLTCB){
  168.         tcb->next->prev = tcb;
  169.     }
  170.     *tcbhead = tcb;
  171.     restore(i_state);
  172. }
  173. /* Remove TCB from whatever hash chain it may be on */
  174. void
  175. unlink_tcb(tcb)
  176. register struct tcb *tcb;
  177. {
  178.     register struct tcb **tcbhead;
  179.     int16 hash_tcb();
  180.     char i_state;
  181.  
  182.     i_state = disable();
  183.     tcbhead = &tcbs[hash_tcb(&tcb->conn)];
  184.     if(*tcbhead == tcb)
  185.         *tcbhead = tcb->next;    /* We're the first one on the chain */
  186.     if(tcb->prev != NULLTCB)
  187.         tcb->prev->next = tcb->next;
  188.     if(tcb->next != NULLTCB)
  189.         tcb->next->prev = tcb->prev;
  190.     restore(i_state);
  191. }
  192. void
  193. setstate(tcb,newstate)
  194. register struct tcb *tcb;
  195. register char newstate;
  196. {
  197.     register char oldstate;
  198.  
  199.     oldstate = tcb->state;
  200.     tcb->state = newstate;
  201.     if(tcb->s_upcall){
  202.         (*tcb->s_upcall)(tcb,oldstate,newstate);
  203.     }
  204.     /* Notify the user that he can begin sending data */
  205.     if(tcb->t_upcall && newstate == ESTABLISHED){
  206.         (*tcb->t_upcall)(tcb,tcb->window - tcb->sndcnt);
  207.     }
  208. }
  209. /* Convert TCP header in host format into mbuf ready for transmission,
  210.  * link in data (if any), and compute checksum
  211.  */
  212. struct mbuf *
  213. htontcp(tcph,data,ph)
  214. struct tcp *tcph;
  215. struct mbuf *data;
  216. struct pseudo_header *ph;
  217. {
  218.     int16 hdrlen;
  219.     struct mbuf *bp;
  220.     register char *cp;
  221.     int16 csum;
  222.  
  223.     hdrlen = (tcph->mss != 0) ? TCPLEN + MSS_LENGTH : TCPLEN;
  224.     
  225.     if((bp = pushdown(data,hdrlen)) == NULLBUF){
  226.         free_p(data);
  227.         return NULLBUF;
  228.     }
  229.     cp = bp->data;
  230.     cp = put16(cp,tcph->source);
  231.     cp = put16(cp,tcph->dest);
  232.     cp = put32(cp,tcph->seq);
  233.     cp = put32(cp,tcph->ack);
  234.     *cp++ = hdrlen << 2;    /* Offset field */
  235.     *cp++ = tcph->flags;
  236.     cp = put16(cp,tcph->wnd);
  237.     if (ph == NULL) {
  238.         cp = put16(cp, tcph->checksum);
  239.     } else {
  240.         *cp++ = 0;    /* Zero out checksum field */
  241.         *cp++ = 0;
  242.     }
  243.     cp = put16(cp,tcph->up);
  244.  
  245.     if(tcph->mss != 0){
  246.         *cp++ = MSS_KIND;
  247.         *cp++ = MSS_LENGTH;
  248.         cp = put16(cp,tcph->mss);
  249.     }
  250.     if (ph) {
  251.         csum = cksum(ph,bp,ph->length);
  252.         cp = &bp->data[16];    /* Checksum field */    
  253.         *cp++ = csum >> 8;
  254.         *cp = csum;
  255.     }
  256.     return bp;
  257. }
  258. /* Pull TCP header off mbuf */
  259. int
  260. ntohtcp(tcph,bpp)
  261. struct tcp *tcph;
  262. struct mbuf **bpp;
  263. {
  264.     int16 hdrlen;
  265.     int16 i,optlen;
  266.     unsigned char *cp, kind;
  267.  
  268.     tcph->source = pull16(bpp);
  269.     tcph->dest = pull16(bpp);
  270.     tcph->seq = pull32(bpp);
  271.     tcph->ack = pull32(bpp);
  272.     if(*bpp == NULLBUF)
  273.         /* Buffer too short to pull off header length */
  274.         return -1;
  275.     hdrlen = (pullchar(bpp) & 0xf0) >> 2;
  276.     tcph->flags = pullchar(bpp);
  277.     tcph->wnd = pull16(bpp);
  278.     tcph->checksum = pull16(bpp);    /* Skip checksum */
  279.     tcph->up = pull16(bpp);
  280.     tcph->mss = 0;
  281.     tcph->optlen = hdrlen - TCPLEN;
  282.  
  283.     /* Check for option field. Only space for one is allowed, but
  284.      * since there's only one TCP option (MSS) this isn't a problem
  285.      */
  286.     if(hdrlen < TCPLEN)
  287.         return -1;    /* Header smaller than legal minimum */
  288.     if(hdrlen == TCPLEN)
  289.         return hdrlen;    /* No options, all done */
  290.  
  291.     if(hdrlen > len_mbuf(*bpp) + TCPLEN){
  292.         /* Remainder too short for options length specified */
  293.         return -1;
  294.     }
  295.     pullup(bpp,tcph->options,tcph->optlen);    /* "Can't fail" */
  296.  
  297.     /* Process options */
  298.     for(cp= (unsigned char *)tcph->options,i=tcph->optlen; i > 0;){
  299.         kind = *cp++;
  300.         switch(kind){
  301.         case EOL_KIND:
  302.             i--;
  303.             cp++;
  304.             return (int)hdrlen;    /* End of options list */
  305.         case NOOP_KIND:
  306.             i--;
  307.             cp++;
  308.             continue;    /* Go look for next option */
  309.         }
  310.         /* All other options have a length field */
  311.         optlen = uchar(*cp++);
  312.  
  313.         /* Process valid multi-byte options */
  314.         switch(kind){
  315.         case MSS_KIND:
  316.             if(optlen == MSS_LENGTH){
  317.                 tcph->mss = get16(cp);
  318.             }
  319.             break;
  320.         }
  321.         optlen = max(2,optlen);    /* Enforce legal minimum */
  322.         i -= optlen;
  323.         cp += optlen - 2;
  324.     }
  325.     return (int)hdrlen;
  326. }
  327.